package ij.hkust.gui.laserCtr.STORM;

import ij.IJ;
import ij.hkust.Camera;
import ij.hkust.Constants;
import ij.hkust.UserSettings;
import ij.hkust.AOTFController.AOTFClient;
import ij.hkust.gui.laserCtr.LaserCtrChooser;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TreeMap;

import QuickPALM.AOTFController;

/**
 * the use for version is 63
 * 
 * @author linshan
 * 
 */
public class StormCmdCtr extends Thread {

	public static StormCmdCtr instance;
//	private AOTFController aotf = new AOTFController();
	private	AOTFClient aotf = AOTFClient.instants;
	private Timer timer = new Timer();
	// ArrayList<StormCmdSender> stormSender = new ArrayList<StormCmdSender>();
	boolean stop = false;
	ArrayList<OneFrame> frames = new ArrayList<OneFrame>();

	public static boolean isFirstTime = true;

	public StormCmdCtr() {
		super();
		// sortFrames();
		instance = this;
	}

	@Override
	public void run() {
		super.run();

		// here we combine our cmds
		for (int i = 0; i < UserSettings.stLasers.size(); i++) {
			String tmpLaser = UserSettings.stLasers.get(i);
			// read frames for each laser
			ArrayList<OneFrame> tmpFrames = new ArrayList<OneFrame>();
			tmpFrames = UserSettings.stFrames.get(tmpLaser);
			int countTime = 0;
			for (int j = 0; j < tmpFrames.size(); j++) {
				OneFrame tmpFrame = tmpFrames.get(j);
				tmpFrame.setCountTime(countTime);
				countTime += tmpFrame.getTime();
			}
		}

		for (int i = 0; i < UserSettings.stLasers.size(); i++) {
			String laser = UserSettings.stLasers.get(i);
			ArrayList<OneFrame> tmpFrames = UserSettings.stFrames.get(laser);

			for (int j = 0; j < tmpFrames.size(); j++) {
				if (tmpFrames.get(j).getPeriodTime() != 0) {
					continue;
				}
				tmpFrames.get(j) .setPeriodTime( tmpFrames.get(tmpFrames.size() - 1).getCountTime()+ tmpFrames.get(tmpFrames.size() - 1).getTime());// +Constants.DELAY_EACH_PERIOD
			}
			// here we add a delay frame to the end of the period, to stop the
			// laser, if we don't do this, the next period will start in
			// advance.
			OneFrame delayFrame = new OneFrame();
			delayFrame.setTime(Constants.DELAY_EACH_PERIOD);
			delayFrame.setIntensity(0);
			delayFrame.setCountTime(tmpFrames.get(tmpFrames.size() - 1)
					.getCountTime()
					+ tmpFrames.get(tmpFrames.size() - 1).getTime());
			delayFrame.setPeriodTime(tmpFrames.get(tmpFrames.size() - 1)
					.getPeriodTime());
			delayFrame.setParent(tmpFrames.get(tmpFrames.size() - 1)
					.getParent());
			frames.addAll(tmpFrames);
			// frames.add(delayFrame);
		}
		// calculate the wait time for each camera command
		int cameraWaitCount = 0;
		// if(isFirstTime){
		for (int i = 0; i < UserSettings.stCamera.size(); i++) {
			UserSettings.stCamera.get(i).setWaitTime(cameraWaitCount);
			cameraWaitCount += UserSettings.stCamera.get(i).getTime();
		}
		for (int i = 0; i < UserSettings.stCamera.size(); i++) {
			UserSettings.stCamera.get(i).setPeriodTime(cameraWaitCount);
		}
		isFirstTime = false;
		// }
		// start to run
		if(aotf == null){
			IJ.error("please close the live window! and then restart!");
			return;
		}
		if ( frames != null) {
			int count = Integer.MAX_VALUE;
			for (int i = 0; i < frames.size(); i++) {
				if (frames.get(i).getCountTime() < count) {
					count = frames.get(i).getCountTime();
				}
			}
			aotf.Write("dau dis\r");
			aotf.Write("dau en\r");
			aotf.Write("dau gain * 255\r");
			aotf.Write("dds f 0 153.7560\r");
			aotf.Write("dds f 1 123.1750\r");
			aotf.Write("dds f 2 113.7680\r");
			aotf.Write("dds f 3 99.2574\r");
			aotf.Write("dds f 4 93.6800\r");
			aotf.Write("dds f 5 77.3082\r");

			int i = 0;
			while (!stop) {
				long start = 0;
				// check the camera
				// IJ.log("start snap::++++++++++++");
				if (i < UserSettings.stCamera.size()) {
					for (int j = 0; j < UserSettings.stLasers.size(); j++) {
						String tmpLaser = UserSettings.stLasers.get(j);
						// read frames for each laser
						ArrayList<OneFrame> tmpFrames = new ArrayList<OneFrame>();
						tmpFrames = UserSettings.stFrames.get(tmpLaser);
						OneFrame tmpFrame = tmpFrames.get(i);
						aotf.Write("dds a "+ Constants.laserID.get(tmpFrame.getLaser())+ " " + tmpFrame.getIntensity() + "\r");
					}
				}
				if (i < UserSettings.stCamera.size()) {
					// IJ.log("start snap::++++++++++++");
					CameraLabel tmpCamera = UserSettings.stCamera.get(i);
					// here we start to snap
//					IJ.log("start snap::");
					start = System.currentTimeMillis();
					// IJ.log(System.currentTimeMillis() + "");
					if (LaserCtrChooser.instance.isUsingCamera()
							&& tmpCamera.isUse()) {
						Camera.snap(tmpCamera.getImageCount(), 0.0,
								Constants.getFilePath(tmpCamera.getChannel()),
								tmpCamera.getChannel());
					}
					if (LaserCtrChooser.instance.isUsingCamera()
							&& !tmpCamera.isUse()) {
						Camera.snap(1, 0.0,Constants.getFilePath(tmpCamera.getChannel()),
								-1);
					}

					tmpCamera.setWaitTime(tmpCamera.getWaitTime()
							+ tmpCamera.getPeriodTime());// jump to the
															// period
					if (tmpCamera.getWaitTime() < count) {
						tmpCamera.setWaitTime(tmpCamera.getWaitTime()+ tmpCamera.getPeriodTime());// jump to the
						// period
					}
					i++;
				} else {
					i = 0;// the next period
				}

			}
		}
	}

	public void stopCmd() {
		stop = true;
		if (timer != null) {
			timer.cancel();
		}
		if (!aotf.IsOpen()) {
			return;
		}
		aotf.Write("dds a 0 0\r");
		aotf.Write("dds a 1 0\r");
		aotf.Write("dds a 2 0\r");
		aotf.Write("dds a 3 0\r");
		aotf.Write("dds a 4 0\r");
		aotf.Write("dds a 5 0\r");
		aotf.Write("dau dis\r");
		//aotf.Close();

	}

	/**
	 * when the command is destroy
	 */
	@Override
	public void destroy() {
		stopCmd();
		super.destroy();
	}

	/**
	 * NO USE here we sort the frame
	 */
	private void sortFrames() {
		for (int i = 0; i < frames.size(); i++) {
			OneFrame tmpi = frames.get(i);
			for (int j = i + 1; j < frames.size(); j++) {
				OneFrame tmpj = frames.get(j);
				if (tmpj.getCountTime() < tmpi.getCountTime()) {
					frames.set(i, tmpj);
					frames.set(j, tmpi);
				}
			}
		}
	}

}
